#include "common.h"
#include "devil1geo.h"

void writemesh(const struct MeshHeader *mh, 
               const struct Mesh *m, 
               const char *filename, 
               unsigned int i) {
    char *fn = (char*)malloc(strlen(filename) + 3 + 4);
    sprintf(fn, "%s_%d.msh", filename, i);
    struct Header h = {
        1,
        0,
        0,
        0,
        0xCCCCCCCC,
        0
    };
    // mesh header offset batches need to be changed for compability with parsing.
    struct MeshHeader newmh = *(mh);
    newmh.offsetBatches = sizeof(struct Header) + sizeof(struct MeshHeader);
    write(fn, (char*)(&h),         sizeof(struct Header));
    append(fn, (char*)(&newmh),    sizeof(struct MeshHeader));



    // batch data the same treatment.
    struct BatchData * newBatches = malloc(newmh.numBatch * sizeof(struct BatchData));
    uint64_t endOfPrevious = 0;
    for (int i = 0; i < newmh.numBatch; i++) {
      newBatches[i] = (m -> b) -> bd[i];
      unsigned int nVertices = m -> b -> bd[i].numVertex;
      if (endOfPrevious == 0) {
        newBatches[i].offsetPositions = newmh.offsetBatches + ( newmh.numBatch * sizeof(struct BatchData));
      }
      else {
        newBatches[i].offsetPositions = endOfPrevious;
      }
      newBatches[i].offsetNormals     = newBatches[i].offsetPositions   + (sizeof(struct Coordinate)  * nVertices);
      newBatches[i].offsetUVs         = newBatches[i].offsetNormals     + (sizeof(struct Coordinate)  * nVertices);
      newBatches[i].offsetBoneIndexes = newBatches[i].offsetUVs         + (sizeof(struct UVs)         * nVertices);
      newBatches[i].offsetBoneWeights = newBatches[i].offsetBoneIndexes + (sizeof(struct BoneIndexes) * nVertices);
      append(fn, (char*)(&newBatches[i]), sizeof(struct BatchData));
      endOfPrevious                   = newBatches[i].offsetBoneWeights + (sizeof(struct BoneWeights) * nVertices);;
    }

    for (int i = 0; i < newmh.numBatch; i++) {
      unsigned int nVertices = m -> b -> bd[i].numVertex;
      append(fn, (char*)(m -> b[i].vd.positions), sizeof(struct Coordinate)  * nVertices);
      append(fn, (char*)(m -> b[i].vd.normals),   sizeof(struct Coordinate)  * nVertices);
      append(fn, (char*)(m -> b[i].vd.u),         sizeof(struct UVs)         * nVertices);
      append(fn, (char*)(m -> b[i].vd.bi),        sizeof(struct BoneIndexes) * nVertices);
      append(fn, (char*)(m -> b[i].vd.bw),        sizeof(struct BoneWeights) * nVertices);
    }

    free(newBatches);
    free(fn);
}

void extractmeshes(const char *filedata,
                   const char *filename,
                   unsigned int filesize) {
    struct Header *h = NULL;
    if (!(DEVIL1GEO.getheader(&h, filedata))|| filesize <= 0) {
        return;
    }
    struct MeshHeader *mh = NULL;
    struct Mesh m;
    m.b = NULL;
    unsigned int i;
    for (i = 0; i < h -> numMesh; i++) {
        DEVIL1GEO.getmeshheader(&mh, i, filedata);
        m.b = (struct Batch*)malloc(sizeof(struct Batch) * (mh -> numBatch));
        if (m.b != NULL) {
            DEVIL1GEO.getmesh(&m, i, filedata, filesize);
            writemesh(mh, &m, filename, i);
            free(m.b);
        }
    } // end for
}


int main(int argc, char ** argv) {
    char *f = argv[1];
    unsigned int bufsize = 0;
    char *buffer         = loadfile(f, &bufsize);
    extractmeshes(buffer, f, bufsize);
    free(buffer);
    return 0;
}


